/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package hcmus.fit.master.sevensea.sprite.ship;

import hcmus.fit.master.sevensea.background.Sea;
import hcmus.fit.master.sevensea.core.AbstractSprite;
import hcmus.fit.master.sevensea.core.Constant;
import hcmus.fit.master.sevensea.sprite.Direction;
import hcmus.fit.master.sevensea.util.Size;

import java.util.ArrayList;
import java.util.List;

import android.graphics.Bitmap;
import android.graphics.Point;

/**
 * 
 * @author hvp
 */
public abstract class Ship extends AbstractSprite {
    public int Status;
    public int DestDirection;
    public int State;
    public int DestX;
    public int DestY;
    public List<List<Bitmap>> FrameLibrary;
    private double _tempX;
    private double _tempY;
    public static List<List<Bitmap>> ShipWhirl;

    public int Delta = 3;

    public Ship(Sea seamap, int x, int y) {
        super(seamap, x, y);
        State = ShipState.Idle;
        DestX = X;
        DestY = Y;
        Status = 4;
        DestDirection = Direction.Right;
        FrameLibrary = null;
        _tempX = X * Constant.CELL_WIDTH * 1.0;
        _tempY = Y * Constant.CELL_HEIGHT * 1.0;
    }

    public Ship(Ship ship) {
        super(ship);
        State = ship.State;
        DestX = ship.DestX;
        DestY = ship.DestY;
        Status = ship.Status;
        DestDirection = ship.DestDirection;
        FrameLibrary = ship.FrameLibrary;
        _tempX = ship._tempX;
        _tempY = ship._tempY;
        Delta = ship.Delta;
    }

    public void moveImmediate(int x, int y) {
        super.moveImmediate(x, y);
        DestX = x;
        DestY = y;
        _tempX = x * Constant.CELL_WIDTH * 1.0;
        _tempY = y * Constant.CELL_HEIGHT * 1.0;
    }

    public boolean isShip() {
        return true;
    }

    // Direction
    // 7 0 1
    // 6 2
    // 5 4 3
    public void Move() {
        switch (DestDirection) {
            case Direction.Top:
                _tempY -= Constant.ShipMoveDeltaY;
                break;
            case Direction.TopRight:
                _tempX += Constant.ShipMoveDeltaX;
                _tempY -= Constant.ShipMoveDeltaY;
                break;
            case Direction.Right:
                _tempX += Constant.ShipMoveDeltaX;
                break;
            case Direction.BottomRight:
                _tempX += Constant.ShipMoveDeltaX;
                _tempY += Constant.ShipMoveDeltaY;
                break;
            case Direction.Bottom:
                _tempY += Constant.ShipMoveDeltaY;
                break;
            case Direction.BottomLeft:
                _tempX -= Constant.ShipMoveDeltaX;
                _tempY += Constant.ShipMoveDeltaY;
                break;
            case Direction.Left:
                _tempX -= Constant.ShipMoveDeltaX;
                break;
            default:
                _tempX -= Constant.ShipMoveDeltaX;
                _tempY -= Constant.ShipMoveDeltaY;
                break;
        }

        setRealPos(new Point((int) Math.floor(_tempX), (int) Math.floor(_tempY)));
    }

    // Direction
    // 7 0 1
    // 6 2
    // 5 4 3
    public void Rotate() {
        int direction = DestDirection;
        int tmp = (Status / 2) - direction;
        if (tmp < 0) {
            if (tmp < -4) {
                Status--;
                if (Status < 0) {
                    Status = 15;
                }
                setFrames((List<Bitmap>) FrameLibrary.get(Status));

            }

            if (tmp >= -4) {
                Status = (Status + 1) % 16;
                setFrames((List<Bitmap>) FrameLibrary.get(Status));

            }
        } else {
            if (tmp < 4) {
                Status--;
                if (Status < 0) {
                    Status = 15;
                }
                setFrames((List<Bitmap>) FrameLibrary.get(Status));

            }

            if (tmp >= 4) {
                Status = (Status + 1) % 16;
                setFrames((List<Bitmap>) FrameLibrary.get(Status));
            }
        }
    }

    public int GetDirection(int destX, int destY, Size size) {

//         int x = (size.Width - Constant.CELL_WIDTH) / 2;
        // int y = (size.Height - Constant.ControlHeight - Constant.CELL_HEIGHT)
        // / 2
        // + Constant.CELL_HEIGHT;
        Point p = seaMap.translateToGlobalView(realPos);
        int x = p.x;
        int y = p.y;
        if (destX >= (x - Constant.CELL_WIDTH) && destX <= x) {
            if (destY >= (y - Constant.CELL_HEIGHT) && destY <= y) {
                DestDirection = 7;
                return 7;
            }

            if (destY >= y && destY <= (y + Constant.CELL_HEIGHT)) {
                DestDirection = 6;
                return 6;
            }

            if (destY >= (y + Constant.CELL_HEIGHT) && destY <= (y + 2 * Constant.CELL_HEIGHT)) {
                DestDirection = 5;
                return 5;
            }
        }

        if (destX >= x && destX <= (x + Constant.CELL_WIDTH)) {
            if (destY >= (y - Constant.CELL_HEIGHT) && destY <= y) {
                DestDirection = 0;
                return 0;
            }

            if (destY >= y && destY <= (y + Constant.CELL_HEIGHT)) {
                return -1;
            }

            if (destY >= (y + Constant.CELL_HEIGHT) && destY <= (y + 2 * Constant.CELL_HEIGHT)) {
                DestDirection = 4;
                return 4;
            }
        }

        if (destX >= (x + Constant.CELL_WIDTH) && destX <= (x + 2 * Constant.CELL_WIDTH)) {
            if (destY >= (y - Constant.CELL_HEIGHT) && destY <= y) {
                DestDirection = 1;
                return 1;
            }

            if (destY >= y && destY <= (y + Constant.CELL_HEIGHT)) {
                DestDirection = 2;
                return 2;
            }

            if (destY >= (y + Constant.CELL_HEIGHT) && destY <= (y + 2 * Constant.CELL_HEIGHT)) {
                DestDirection = 3;
                return 3;
            }
        }
        return -2;
    }

    public boolean FinishMove() {
        if (getRealPos().x == DestX * Constant.CELL_WIDTH
                && getRealPos().y == DestY * Constant.CELL_HEIGHT) {
            _tempX = DestX * Constant.CELL_WIDTH * 1.0;
            _tempY = DestY * Constant.CELL_HEIGHT * 1.0;
            return true;
        }
        return false;
    }

    public boolean FinishRotate() {
        if (Status == (DestDirection * 2)) {
            return true;
        }
        return false;
    }

    public void GetDestination() {
        int direction = DestDirection;
        switch (direction) {
            case 0:
                DestX = X;
                DestY = (Y - 1 >= 0) ? Y - 1 : Y;
                break;
            case 1:
                DestX = (X + 1 < Constant.Width && Y - 1 >= 0) ? X + 1 : X;
                DestY = (X + 1 < Constant.Width && Y - 1 >= 0) ? Y - 1 : Y;
                break;
            case 2:
                DestX = (X + 1 < Constant.Width) ? X + 1 : X;
                DestY = Y;
                break;
            case 3:
                DestX = (X + 1 < Constant.Width && Y + 1 < Constant.Height) ? X + 1 : X;
                DestY = (X + 1 < Constant.Width && Y + 1 < Constant.Height) ? Y + 1 : Y;
                break;
            case 4:
                DestX = X;
                DestY = (Y + 1 < Constant.Height) ? Y + 1 : Y;
                break;
            case 5:
                DestX = (X - 1 >= 0 && Y + 1 < Constant.Height) ? X - 1 : X;
                DestY = (X - 1 >= 0 && Y + 1 < Constant.Height) ? Y + 1 : Y;
                break;
            case 6:
                DestX = (X - 1 >= 0) ? X - 1 : X;
                DestY = Y;
                break;
            default:
                DestX = (X - 1 >= 0 && Y - 1 >= 0) ? X - 1 : X;
                DestY = (X - 1 >= 0 && Y - 1 >= 0) ? Y - 1 : Y;
                break;
        }
    }

    public boolean update() {
        switch (State) {
            case ShipState.Idle:
                break;
            case ShipState.Moving:
                if (FinishMove()) {
                    State = ShipState.Idle;
                    X = (getRealPos().x) / Constant.CELL_WIDTH;
                    Y = (getRealPos().y) / Constant.CELL_HEIGHT;
                    if (getSeaMap().map[Y][X] != null) {
                        if (getSeaMap().map[Y][X].isIsland() || getSeaMap().map[Y][X].isRubble()) {
                            getSeaMap().boardControl._Score.SCORE += GetScore();
                            getSeaMap().items.remove(this);
                            getSeaMap().createExplosion(X, Y);
                        } else if (getSeaMap().map[Y][X].isShip()) {
                            if (getSeaMap().map[Y][X].equals(getSeaMap().mainShip))
                                getSeaMap().boardControl._Score.SCORE += GetScore();
                            else
                                getSeaMap().boardControl._Score.SCORE += GetScore()
                                        + ((Ship) getSeaMap().map[Y][X]).GetScore();

                            getSeaMap().items.remove(this);
                            getSeaMap().items.remove(getSeaMap().map[Y][X]);
                            getSeaMap().createRubble(X, Y);
                            getSeaMap().createExplosion(X, Y);
                        } else if (getSeaMap().map[Y][X].isWhirl()) {
                            // move to another place
                            getSeaMap().boardControl._Score.SCORE += GetScore();
                            getSeaMap().items.remove(this);
                            getSeaMap().createSplash(X, Y);
                        }
                    } else {
                        getSeaMap().map[Y][X] = this;
                    }
                    getSeaMap().busy--;
                } else {
                    Move();
                }
                break;
            case ShipState.Rotating:
                if (FinishRotate()) {
                    State = ShipState.Moving;
                } else {
                    Rotate();
                }
                break;
        }
        setIndex((getIndex() + 1) % getNbOfFrame());
        return true;
    }

    public void DoWhirl() {
        // Status = 7;
        setFrames((List<Bitmap>) ShipWhirl.get(0));
        setIndex(0);
        Delta = Math.abs(Delta);
        State = ShipState.Whirling;
    }

    public void StopWhirl() {
        Status = 4;
        setFrames((List<Bitmap>) FrameLibrary.get(Status));
        setIndex(0);
        State = ShipState.Idle;
        getSeaMap().map[Y][X] = this;
        getSeaMap().enemyMove();
    }

    public void GetDirection(int targetX, int targetY) {
        DestDirection = 0;
    }

    public static List<List<Bitmap>> GetResource(Bitmap resource, int maxX, int maxY,
            int numerator, int denominator) {
        List<List<Bitmap>> rs = new ArrayList<List<Bitmap>>();
        // rs.Clear();
        int w = resource.getWidth() / maxX;
        int h = resource.getHeight() / maxY;
        // imgatt.SetColorKey(resource.GetPixel(0, 0), resource.GetPixel(0, 0));

        for (int i = 0; i < maxX; i++) {
            List<Bitmap> tmp = new ArrayList<Bitmap>();
            for (int j = 0; j < maxY; j++) {
                tmp.add(Bitmap.createBitmap(resource, i * w, j * h, w, h));
            }
            rs.add(tmp);
        }
        return rs;
    }

    public int GetScore() {
        // throw new Exception("Not Implement");
        return 0;
    }

    public boolean ItemAvailable(int direction) {
        Point p = GetPosition(direction);
        if (p.x == -1) {
            return true;
        }
        return getSeaMap().map[p.y][p.x] != null;
    }

    public Point GetPosition(int direction) {
        switch (direction) {
            case 0:
                if (Y == 0) {
                    return new Point(-1, -1);
                }
                return new Point(X, Y - 1);
            case 1:
                if (Y == 0 || X == Constant.Width - 1) {
                    return new Point(-1, -1);
                }
                return new Point(X + 1, Y - 1);
            case 2:
                if (X == Constant.Width - 1) {
                    return new Point(-1, -1);
                }
                return new Point(X + 1, Y);
            case 3:
                if (Y == Constant.Height - 1 || X == Constant.Width - 1) {
                    return new Point(-1, -1);
                }
                return new Point(X + 1, Y + 1);
            case 4:
                if (Y == Constant.Height - 1) {
                    return new Point(-1, -1);
                }
                return new Point(X, Y + 1);
            case 5:
                if (Y == Constant.Height - 1 || X == 0) {
                    return new Point(-1, -1);
                }
                return new Point(X - 1, Y + 1);
            case 6:
                if (X == 0) {
                    return new Point(-1, -1);
                }
                return new Point(X - 1, Y);
            case 7:
                if (Y == 0 || X == 0) {
                    return new Point(-1, -1);
                }
                return new Point(X - 1, Y - 1);
        }
        return new Point(-1, -1);
    }
}
